home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / FinderFlocks / FinderFun / AppleEventUtilities.cp next >
Text File  |  1996-06-22  |  75KB  |  2,209 lines

  1. /*
  2.     File:        AppleEventUtilities.cp
  3.  
  4.     Contains:    C++ Wrappers for Apple Event manager
  5.  
  6. */
  7.  
  8. #ifndef __APPLEEVENTUTILITIES__
  9. #include "AppleEventUtilities.h"
  10. #endif
  11.  
  12. #ifndef __ASREGISTRY__
  13. #include <ASRegistry.h>
  14. #endif
  15.  
  16. #ifndef Exceptions_h
  17. #include "Exceptions.h"
  18. #endif
  19.  
  20. #ifndef __OSUTILS__
  21. #include <OSUtils.h>
  22. #endif
  23.  
  24. #ifndef __SCRIPT__
  25. #include <Script.h>
  26. #endif
  27.  
  28. #ifndef __APPLEEVENTS__
  29. #include <AppleEvents.h>
  30. #endif
  31.  
  32. #ifndef __AEOBJECTS__
  33. #include <AEObjects.h>
  34. #endif
  35.  
  36. #ifndef __ALIASES__
  37. #include <Aliases.h>
  38. #endif
  39.  
  40. #ifndef __AEOBJECTPACKING__
  41. #include <AEPackObject.h>
  42. #endif
  43.  
  44. #ifndef __AEREGISTRY__
  45. #include <AERegistry.h>
  46. #endif
  47.  
  48. #ifndef __GESTALTEQU__
  49. #include <GestaltEqu.h>
  50. #endif
  51.  
  52. #pragma segment AEMStuff
  53.  
  54.  
  55. MakeTokenDescriptorProcPtr gNullContainerCreationProc = nil;
  56. ProcessDescriptorProcPtr gPreResolveProc = nil;
  57. MergeTokensProcPtr gMergeTokensProc = nil;
  58.  
  59. short TDescriptor::fCallbackFlags = kAEIDoMinimum;
  60.  
  61. //----------------------------------------------------------------------------------------
  62. // InstallNullContainerCreationProc: 
  63. //
  64. // The null container creation proc is used by TDescriptor::Resolve whenever it receives
  65. // a null descriptor to resolve.  This function is used to create a token for the null
  66. // container.
  67. //----------------------------------------------------------------------------------------
  68. void InstallNullContainerCreationProc(MakeTokenDescriptorProcPtr creationProc)
  69.     {
  70.     gNullContainerCreationProc = creationProc;
  71.     } // InstallNullContainerCreationProc 
  72.  
  73. //----------------------------------------------------------------------------------------
  74. // InstallPreResolveProc: 
  75. //
  76. // The PreResolveProc is called by TDescriptor::Resolve before it actually calls
  77. // AEResolve.  This allows special procs to handle things not understood by AEResolve
  78. // (alias records, for example).
  79. //----------------------------------------------------------------------------------------
  80. void InstallPreResolveProc(ProcessDescriptorProcPtr preResolveProc)
  81.     {
  82.     gPreResolveProc = preResolveProc;
  83.     } // InstallPreResolveProc 
  84.  
  85. //----------------------------------------------------------------------------------------
  86. // InstallMergeTokensProc: 
  87. //
  88. // The MergeTokensProc is called by TTokenDescriptor::AdoptToken whenever it needs to add
  89. // a token object to any token descriptor that already contains a token.  The merge token
  90. // proc is provided with two TAbstractScriptableObject*'s; it must return a
  91. // TAbstractScriptableObject* that has adopted the two tokens passed to it.
  92. //----------------------------------------------------------------------------------------
  93. void InstallMergeTokensProc(MergeTokensProcPtr mergeTokensProc)
  94.     {
  95.     gMergeTokensProc = mergeTokensProc;
  96.     } // InstallMergeTokensProc 
  97.  
  98. //----------------------------------------------------------------------------------------
  99. // CreateNullContainerToken: 
  100. //----------------------------------------------------------------------------------------
  101. TTokenDescriptor CreateNullContainerToken()
  102.     {
  103.     TTokenDescriptor nullContainer;
  104.     
  105.     if(gNullContainerCreationProc != nil)
  106.         nullContainer = (*gNullContainerCreationProc)();
  107.     
  108.     return nullContainer;
  109.     } // CreateNullContainerToken 
  110.  
  111. //========================================================================================
  112. // CLASS TDescriptor
  113. //
  114. // Class TDescriptor is a wrapper class for AEDesc objects.
  115. //========================================================================================
  116.  
  117.  
  118. //----------------------------------------------------------------------------------------
  119. // TDescriptor::Dispose:
  120. //
  121. // Disposed of the descriptor and the data stored inside it.
  122. //----------------------------------------------------------------------------------------
  123. void TDescriptor::Dispose()
  124.     {
  125.     FailErr(AEDisposeDesc(*this));
  126.     } // TDescriptor::Dispose 
  127.  
  128. //----------------------------------------------------------------------------------------
  129. // TDescriptor::AttemptCoercion:
  130. //
  131. // Try to coerce the type of the descriptor to something else.  This method will
  132. // NOT fail if the coercion could not be done.
  133. //----------------------------------------------------------------------------------------
  134. OSErr TDescriptor::AttemptCoercion(DescType typeToCoerceTo)
  135.     {
  136.     OSErr err = noErr;
  137.     
  138.     if(this->DescriptorType() != typeToCoerceTo)
  139.         {
  140.         TDescriptor tempDescriptor;
  141.         
  142.         // If AECoerceDesc returns a non-zero result code, then
  143.         // tempDescriptor will be typeNull, and we don't need to
  144.         // worry about disposing of it.
  145.         err = AECoerceDesc(*this,typeToCoerceTo,(AEDesc*)&tempDescriptor);
  146.  
  147.         if(err == noErr)
  148.             {            
  149.             Try
  150.                 {
  151.                 Handle initialHandle = this->DataHandle();
  152.                 Handle coercedHandle = tempDescriptor.DataHandle();
  153.                 
  154.                 //
  155.                 // If doing a coerce-in-place, try to do a SetHandleSize
  156.                 // and then a BlockMove so that we end up using the same
  157.                 // handle when we exit as we had when we entered.  To do
  158.                 // otherwise is to invite double-dispose/memory leak problems
  159.                 // if some other peice of code still has a reference to
  160.                 // the descriptor before it was coerced
  161.                 //
  162.                 if((initialHandle != nil) && (coercedHandle != nil))
  163.                     {
  164.                     Size coercedSize = GetHandleSize(coercedHandle);
  165.                     SetHandleSize(initialHandle, coercedSize);
  166.                     FailErr(MemError());
  167.                     BlockMove(*coercedHandle, *initialHandle, coercedSize);
  168.                     this->fDescriptorType = tempDescriptor.DescriptorType();
  169.                     tempDescriptor.Dispose();
  170.                     }
  171.                 //
  172.                 // There are a couple of rare cases (typeTrue and typeFalse)
  173.                 // where the data handle is nil
  174.                 //
  175.                 else
  176.                     {
  177.                     //
  178.                     // It's undesirable to go from a nil-handle to a non-nil
  179.                     // handle, or visa-versa.  Don't do it.  Use 'Coerce'
  180.                     // rather than 'CoerceInPlace' if this is necessary.
  181.                     //
  182.                     if((initialHandle != nil) || (coercedHandle != nil))
  183.                         DebugStr("\pPotentially undesirable coerce-in-place");
  184.                     //
  185.                     // Try to dispose of the old descriptor (ignoring errors)
  186.                     // and then plug in the values from the coerced descriptor
  187.                     //
  188.                     AEDisposeDesc(*this);
  189.                     this->AdoptDesc(tempDescriptor);
  190.                     }
  191.                 }
  192.             Catch(err)
  193.                 {
  194.                 tempDescriptor.Dispose();
  195.                 }
  196.             }
  197.         }
  198.     
  199.     return err;
  200.     } // TDescriptor::AttemptCoercion 
  201.  
  202. //----------------------------------------------------------------------------------------
  203. // TDescriptor::CoerceInPlace:
  204. //
  205. // Require that this object be coerced to the specified data type.  This method will
  206. // fail if the coercion does not work.
  207. //----------------------------------------------------------------------------------------
  208. void TDescriptor::CoerceInPlace(DescType typeToCoerceTo)
  209.     {
  210.     FailErr(this->AttemptCoercion(typeToCoerceTo));
  211.     } // TDescriptor::CoerceInPlace 
  212.  
  213. //----------------------------------------------------------------------------------------
  214. // TDescriptor::Coerce:
  215. //
  216. // Require that this object be coerced to the specified data type.  This method will
  217. // fail if the coercion does not work.
  218. //----------------------------------------------------------------------------------------
  219. TDescriptor TDescriptor::Coerce(DescType typeToCoerceTo) const
  220.     {
  221.     TDescriptor coercedDescriptor;
  222.     
  223.     FailErr(AECoerceDesc(*this,typeToCoerceTo,coercedDescriptor));
  224.     
  225.     return coercedDescriptor;
  226.     } // TDescriptor::Coerce 
  227.     
  228. //----------------------------------------------------------------------------------------
  229. // TDescriptor::CoerceToStandardType:
  230. //
  231. // This method attempts to coerce its data into some form of standard type
  232. // (e.g. typeChar or typeLongInteger).  It is really annoying that someone can
  233. // invent yet another data type that is coercable to text or as a long integer,
  234. // but we wouldn't have any way to know that such a coercion should be attempted.
  235. // typeMagnitude and typeEnumeration could throw us for a loop too.
  236. //
  237. // ••• In short, I really hate this routine, but I'm not sure what else to do about it.
  238. //----------------------------------------------------------------------------------------
  239. void TDescriptor::CoerceToStandardType()
  240.     {
  241.     switch(this->DescriptorType())
  242.         {
  243.         case typeAEText:
  244.         case typeIntlText:
  245.         case typeStyledText:
  246.             {
  247.             this->CoerceInPlace(typeChar);
  248.             break;
  249.             }
  250.         
  251.         case typeShortInteger:
  252.             {
  253.             this->CoerceInPlace(typeLongInteger);
  254.             break;
  255.             }
  256.         }
  257.     } // TDescriptor::CoerceToStandardType 
  258.     
  259. //----------------------------------------------------------------------------------------
  260. // TDescriptor::Clone:
  261. //
  262. // Return an exact copy of this descriptor
  263. //----------------------------------------------------------------------------------------
  264. TDescriptor TDescriptor::Clone() const
  265.     {
  266.     TDescriptor clonedDescriptor;
  267.     
  268.     FailErr(AEDuplicateDesc(*this, (AEDesc*)&clonedDescriptor));
  269.     
  270.     return clonedDescriptor;
  271.     } // TDescriptor::Clone 
  272.  
  273. //----------------------------------------------------------------------------------------
  274. // TDescriptor::CopyDesc: 
  275. //----------------------------------------------------------------------------------------
  276. void TDescriptor::CopyDesc(const TDescriptor& desc)
  277.     {
  278.     FailErr(AEDuplicateDesc((AEDesc*)&desc, *this));
  279.     } // TDescriptor::CopyDesc 
  280.  
  281. //----------------------------------------------------------------------------------------
  282. // TDescriptor::AdoptDesc: 
  283. //----------------------------------------------------------------------------------------
  284. void TDescriptor::AdoptDesc(TDescriptor& desc)
  285.     {
  286.     //
  287.     // It would be very tempting to set 'desc' to the null descriptor now
  288.     // that we have adopted it here.  That would be a bad idea, though, because
  289.     // we might intend this descriptor to actually be just a reference to
  290.     // the adopted desc, and not actually the new 'owner' of the data.
  291.     //
  292.     this->AdoptHandle(desc.DescriptorType(), desc.DataHandle());
  293.     } // TDescriptor::AdoptDesc 
  294.  
  295. //----------------------------------------------------------------------------------------
  296. // TDescriptor::CreateList:
  297. //
  298. // Create an empty descriptor list or AERecord with factored data.
  299. //
  300. // n.b.    It is better to call MakeList, MakeEmptyList or MakeAERecord rather than
  301. // using TDescriptor::CreateList directly.
  302. //----------------------------------------------------------------------------------------
  303. void TDescriptor::CreateList(Boolean isRecord, Ptr factoringPtr, Size factoredSize)
  304.     {
  305.     FailErr(AECreateList(factoringPtr, factoredSize, isRecord, *this));
  306.     } // TDescriptor::CreateList 
  307.  
  308. //----------------------------------------------------------------------------------------
  309. // TDescriptor::MakeNull: 
  310. //----------------------------------------------------------------------------------------
  311. void TDescriptor::MakeNull()
  312.     {
  313.     this->AdoptHandle(typeNull, nil);
  314.     } // TDescriptor::MakeNull 
  315.  
  316. //----------------------------------------------------------------------------------------
  317. // TDescriptor::AdoptHandle:
  318. //
  319. // Assign some data and a type directly to the descriptor
  320. //----------------------------------------------------------------------------------------
  321. void TDescriptor::AdoptHandle(DescType dataType, Handle dataHandle)
  322.     {
  323.     fDescriptorType = dataType;
  324.     fDataHandle = dataHandle;
  325.     } // TDescriptor::AdoptHandle
  326.  
  327. //----------------------------------------------------------------------------------------
  328. // TDescriptor::CopyData: 
  329. //----------------------------------------------------------------------------------------
  330. void TDescriptor::CopyData(const DescType typeCode, const Ptr data, const Size length)
  331.     {
  332.     FailErr(AECreateDesc(typeCode, data, length, *this));
  333.     } // TDescriptor::CopyData 
  334.  
  335. //----------------------------------------------------------------------------------------
  336. // TDescriptor::MakeBoolean: 
  337. //----------------------------------------------------------------------------------------
  338. void TDescriptor::MakeBoolean(const Boolean data)
  339.     {
  340.     this->CopyData(typeBoolean, (Ptr)&data, sizeof(Boolean));
  341.     } // TDescriptor::MakeBoolean 
  342.     
  343. //----------------------------------------------------------------------------------------
  344. // TDescriptor::MakeLong: 
  345. //----------------------------------------------------------------------------------------
  346. void TDescriptor::MakeLong(const long data)
  347.     {
  348.     this->CopyData(typeLongInteger, (Ptr)&data, sizeof(long));
  349.     } // TDescriptor::MakeLong
  350.  
  351. //----------------------------------------------------------------------------------------
  352. // TDescriptor::MakeUnsignedLong: 
  353. //----------------------------------------------------------------------------------------
  354. void TDescriptor::MakeUnsignedLong(const unsigned long data)
  355.     {
  356.     this->CopyData(typeMagnitude, (Ptr)&data, sizeof(unsigned long));
  357.     } // TDescriptor::MakeUnsignedLong
  358.  
  359. //----------------------------------------------------------------------------------------
  360. // TDescriptor::MakeEnumeration: 
  361. //----------------------------------------------------------------------------------------
  362. void TDescriptor::MakeEnumeration(const DescType enumeration)
  363.     {
  364.     this->CopyData(typeEnumeration, (Ptr)&enumeration, sizeof(enumeration));
  365.     } // TDescriptor::MakeEnumeration 
  366.  
  367. //----------------------------------------------------------------------------------------
  368. // TDescriptor::MakeDescType: 
  369. //----------------------------------------------------------------------------------------
  370. void TDescriptor::MakeDescType(const DescType data)
  371.     {
  372.     this->CopyData(typeType, (Ptr)&data, sizeof(DescType));
  373.     } // TDescriptor::MakeDescType 
  374.  
  375. //----------------------------------------------------------------------------------------
  376. // TDescriptor::MakeKeyword: 
  377. //----------------------------------------------------------------------------------------
  378. void TDescriptor::MakeKeyword(const AEKeyword theKeyword)
  379.     {
  380.     this->CopyData(typeKeyword, (Ptr)&theKeyword, sizeof(AEKeyword));
  381.     } // TDescriptor::MakeKeyword 
  382.  
  383. //----------------------------------------------------------------------------------------
  384. // TDescriptor::MakeOrdinal: 
  385. //----------------------------------------------------------------------------------------
  386. void TDescriptor::MakeOrdinal(const DescType data)
  387.     {
  388.     this->CopyData(typeAbsoluteOrdinal, (Ptr)&data, sizeof(DescType));
  389.     } // TDescriptor::MakeOrdinal 
  390.     
  391. //----------------------------------------------------------------------------------------
  392. // TDescriptor::MakeTypeOrInteger:
  393. //
  394. // This is useful for debugging; it makes a 'type' if the data
  395. // appears to consist of printable characters (e.g. 'ABCD'), but
  396. // otherwise it makes an integer (e.g. -12).
  397. //----------------------------------------------------------------------------------------
  398. void TDescriptor::MakeTypeOrInteger(const DescType data)
  399.     {
  400.     if(((data >= 'A000') && (data <= 'Zzzz')) || ((data >= 'a000') && (data <= 'zzzz')))
  401.         this->MakeDescType(data);
  402.     else
  403.         this->MakeLong(data);
  404.     } // TDescriptor::MakeTypeOrInteger 
  405.  
  406. //----------------------------------------------------------------------------------------
  407. // TDescriptor::MakePoint: 
  408. //----------------------------------------------------------------------------------------
  409. void TDescriptor::MakePoint(const Point& thePoint)
  410.     {
  411.     this->CopyData(typeQDPoint, (Ptr)&thePoint, sizeof(Point));
  412.     } // TDescriptor::MakePoint 
  413.  
  414. //----------------------------------------------------------------------------------------
  415. // TDescriptor::MakePoint: 
  416. //----------------------------------------------------------------------------------------
  417. void TDescriptor::MakePoint(const short h, const short v)
  418.     {
  419.     Point thePoint;
  420.     
  421.     thePoint.v = v;
  422.     thePoint.h = h;
  423.     this->MakePoint(thePoint);
  424.     } // TDescriptor::MakePoint 
  425.  
  426. //----------------------------------------------------------------------------------------
  427. // TDescriptor::MakeRect: 
  428. //----------------------------------------------------------------------------------------
  429. void TDescriptor::MakeRect(const Rect& theRect)
  430.     {
  431.     this->CopyData(typeQDRectangle, (Ptr)&theRect, sizeof(Rect));
  432.     } // TDescriptor::MakeRect 
  433.  
  434. //----------------------------------------------------------------------------------------
  435. // TDescriptor::MakeString: 
  436. //----------------------------------------------------------------------------------------
  437. void TDescriptor::MakeString(Str255 data)
  438.     {
  439.     Size length = data[0];
  440.     
  441.     this->CopyData(typeChar, (Ptr)&data[1], length);
  442.     } // TDescriptor::MakeString 
  443.  
  444. //----------------------------------------------------------------------------------------
  445. // TDescriptor::MakeDateTimeRec: 
  446. //----------------------------------------------------------------------------------------
  447. void TDescriptor::MakeDateTimeRec(const DateTimeRec dateTime)
  448.     {
  449.     this->CopyData(typeDateTimeRec, (Ptr)&dateTime, sizeof(DateTimeRec));
  450.     } // TDescriptor::MakeDateTimeRec 
  451.  
  452. //----------------------------------------------------------------------------------------
  453. // TDescriptor::MakeDateTimeRec: 
  454. //----------------------------------------------------------------------------------------
  455. void TDescriptor::MakeDateTimeRec(const long secsSince1904)
  456.     {
  457.     DateTimeRec dateTime;
  458.     
  459.     //
  460.     // Let the OSUtilities do the hard work of converting seconds
  461.     // since 1904 into a DateTimeRec
  462.     //
  463.     Secs2Date(secsSince1904,&dateTime);
  464.     this->MakeDateTimeRec(dateTime);
  465.     } // TDescriptor::MakeDateTimeRec 
  466.  
  467. //----------------------------------------------------------------------------------------
  468. // TDescriptor::MakeLongDateTimeRec: 
  469. //----------------------------------------------------------------------------------------
  470. void TDescriptor::MakeLongDateTimeRec(const LongDateRec dateTime)
  471.     {
  472.     this->CopyData(typeLongDateTimeRec, (Ptr)&dateTime, sizeof(LongDateRec));
  473.     } // TDescriptor::MakeLongDateTimeRec 
  474.  
  475. //----------------------------------------------------------------------------------------
  476. // TDescriptor::MakeLongDateTimeRec: 
  477. //----------------------------------------------------------------------------------------
  478. void TDescriptor::MakeLongDateTimeRec(const DateTimeRec dateTime)
  479.     {
  480.     LongDateRec longDateTime;
  481.         
  482.     longDateTime.od.eraAlt = 0;
  483.     longDateTime.od.oldDate = dateTime;
  484.     
  485.     this->MakeLongDateTimeRec(longDateTime);
  486.     } // TDescriptor::MakeLongDateTimeRec 
  487.  
  488. //----------------------------------------------------------------------------------------
  489. // TDescriptor::MakeLongDateTimeRec: 
  490. //----------------------------------------------------------------------------------------
  491. void TDescriptor::MakeLongDateTimeRec(LongDateTime lsecs)
  492.     {
  493.     LongDateRec longDateTime;
  494.     
  495.     LongSecs2Date(&lsecs, &longDateTime);
  496.     this->MakeLongDateTimeRec(longDateTime);
  497.     } // TDescriptor::MakeLongDateTimeRec 
  498.  
  499. //----------------------------------------------------------------------------------------
  500. // TDescriptor::MakeLongDateTime: 
  501. //----------------------------------------------------------------------------------------
  502. void TDescriptor::MakeLongDateTime(const LongDateTime lsecs)
  503.     {
  504.     this->CopyData(typeLongDateTime, (Ptr)&lsecs, sizeof(LongDateTime));
  505.     } // TDescriptor::MakeLongDateTime 
  506.  
  507. //----------------------------------------------------------------------------------------
  508. // TDescriptor::MakeFSS: 
  509. //----------------------------------------------------------------------------------------
  510. void TDescriptor::MakeFSS(const FSSpec& spec)
  511.     {
  512.     this->CopyData(typeFSS, (Ptr)&spec, sizeof(FSSpec));
  513.     } // TDescriptor::MakeFSS 
  514.  
  515. //----------------------------------------------------------------------------------------
  516. // TDescriptor::AdoptAlias: 
  517. //
  518. // Takes the provided alias handle and keeps it forever.
  519. //----------------------------------------------------------------------------------------
  520. void TDescriptor::AdoptAlias(Handle alias)
  521.     {
  522.     this->AdoptHandle(typeAlias, alias);
  523.     } // TDescriptor::AdoptAlias 
  524.     
  525. //----------------------------------------------------------------------------------------
  526. // TDescriptor::MakeAlias: 
  527. //
  528. // You would think that someone would have spent five minutes to make a coercion
  529. // handler that goes from FSSpecs to Alias records, but nooooooo...
  530. //----------------------------------------------------------------------------------------
  531. void TDescriptor::MakeAlias(FSSpec& spec)
  532.     {
  533.     AliasHandle alias;
  534.     
  535.     FailErr(NewAliasMinimal(&spec, &alias));
  536.     this->AdoptAlias((Handle)alias);
  537.     } // TDescriptor::MakeAlias 
  538.  
  539. //----------------------------------------------------------------------------------------
  540. // TDescriptor::MakeProcessSerialNumber: 
  541. //----------------------------------------------------------------------------------------
  542. void TDescriptor::MakeProcessSerialNumber(ProcessSerialNumber psn)
  543.     {
  544.     this->CopyData(typeProcessSerialNumber, (Ptr)&psn, sizeof(ProcessSerialNumber));
  545.     } // TDescriptor::MakeProcessSerialNumber 
  546.  
  547. //----------------------------------------------------------------------------------------
  548. // TDescriptor::MakeObjectSpecifier: 
  549. //----------------------------------------------------------------------------------------
  550. void TDescriptor::MakeObjectSpecifier(DescType desiredClass, TDescriptor container, DescType keyForm, TDescriptor keyData, Boolean disposeInputs)
  551.     {
  552.     FailErr(CreateObjSpecifier(desiredClass,container,keyForm,keyData,disposeInputs,*this));
  553.     } // TDescriptor::MakeObjectSpecifier 
  554.  
  555. //----------------------------------------------------------------------------------------
  556. // TDescriptor::MakeCompDescriptor: 
  557. //----------------------------------------------------------------------------------------
  558. void TDescriptor::MakeCompDescriptor(DescType comparisonOperator, DescType propertyIdentifier, TDescriptor compareWith, Boolean disposeInputs)
  559.     {
  560.     TDescriptor operand1;
  561.     TDescriptor propertyIDDesc;
  562.     TDescriptor objectBeingExamined;
  563.     
  564.     //
  565.     // 'objectBeingExamined' is a special object specifier that only
  566.     // has meaning in the context of a comparison descriptor
  567.     //
  568.     objectBeingExamined.AdoptHandle(typeObjectBeingExamined,nil);
  569.     
  570.     //
  571.     // Operand1 is "fPropertyIdentifier of (object being examined)"
  572.     //
  573.     propertyIDDesc.MakeDescType(propertyIdentifier);
  574.     operand1.MakeObjectSpecifier(cProperty, objectBeingExamined, formPropertyID, propertyIDDesc, true);
  575.  
  576.     //
  577.     // Make a compDescriptor of operand1 compared with (fComparisonOperator) fCompareWith
  578.     //
  579.     CreateCompDescriptor(comparisonOperator, operand1, compareWith, disposeInputs, *this);
  580.     } // TDescriptor::MakeCompDescriptor 
  581.  
  582. //----------------------------------------------------------------------------------------
  583. // TDescriptor::GetBlock: 
  584. //----------------------------------------------------------------------------------------
  585. void TDescriptor::GetBlock(Ptr data, Size length, DescType desiredType) const
  586.     {
  587.     if(this->DataHandleIsNil())
  588.         FailErr(errAECantSupplyType);
  589.     
  590.     if(this->DescriptorType() != desiredType)
  591.         {
  592.         TDescriptor coerceData;
  593.         
  594.         coerceData = this->Coerce(desiredType);
  595.         coerceData.GetBlock(data,length,desiredType);
  596.         coerceData.Dispose();
  597.         }
  598.     else
  599.         {
  600.         //
  601.         // It would be just wrong to have a situation where a
  602.         // descriptor is of the requested type, but not of the
  603.         // requested length.  This method is only usable for
  604.         // fixed-size blocks
  605.         //
  606.         if(GetHandleSize(fDataHandle) != length)
  607.             {
  608.             FailErr(errAECorruptData);
  609.             }
  610.  
  611.         BlockMove(*fDataHandle, data, length);
  612.         }
  613.     } // TDescriptor::GetBlock 
  614.  
  615. //----------------------------------------------------------------------------------------
  616. // TDescriptor::GetLong: 
  617. //----------------------------------------------------------------------------------------
  618. long TDescriptor::GetLong() const
  619.     {
  620.     long result = 0;
  621.  
  622.     this->GetBlock((Ptr)&result, sizeof(long), typeLongInteger);
  623.  
  624.     return result;
  625.     } // TDescriptor::GetLong 
  626.     
  627. //----------------------------------------------------------------------------------------
  628. // TDescriptor::GetBoolean: 
  629. //----------------------------------------------------------------------------------------
  630. Boolean TDescriptor::GetBoolean() const
  631.     {
  632.     Boolean result = 0;
  633.  
  634.     this->GetBlock((Ptr)&result, sizeof(Boolean), typeBoolean);
  635.  
  636.     return result;
  637.     } // TDescriptor::GetBoolean 
  638.  
  639. //----------------------------------------------------------------------------------------
  640. // TDescriptor::GetDescType: 
  641. //----------------------------------------------------------------------------------------
  642. DescType TDescriptor::GetDescType() const
  643.     {
  644.     DescType result = 0;
  645.     
  646.     this->GetBlock((Ptr)&result, sizeof(DescType), typeType);
  647.     
  648.     return result;
  649.     } // TDescriptor::GetDescType 
  650.  
  651. //----------------------------------------------------------------------------------------
  652. // TDescriptor::GetKeyword: 
  653. //----------------------------------------------------------------------------------------
  654. AEKeyword TDescriptor::GetKeyword() const
  655.     {
  656.     AEKeyword result = 0;
  657.     
  658.     this->GetBlock((Ptr)&result, sizeof(AEKeyword), typeKeyword);
  659.     
  660.     return result;
  661.     } // TDescriptor::GetKeyword 
  662.     
  663. //----------------------------------------------------------------------------------------
  664. // TDescriptor::GetEnumeration: 
  665. //----------------------------------------------------------------------------------------
  666. DescType TDescriptor::GetEnumeration() const
  667.     {
  668.     DescType result = 0;
  669.     
  670.     this->GetBlock((Ptr)&result, sizeof(DescType), typeEnumeration);
  671.     
  672.     return result;
  673.     } // TDescriptor::GetEnumeration 
  674.  
  675. //----------------------------------------------------------------------------------------
  676. // TDescriptor::GetOrdinal: 
  677. //----------------------------------------------------------------------------------------
  678. DescType TDescriptor::GetOrdinal() const
  679.     {
  680.     DescType result = 0;
  681.     
  682.     this->GetBlock((Ptr)&result, sizeof(DescType), typeAbsoluteOrdinal);
  683.     
  684.     return result;
  685.     } // TDescriptor::GetOrdinal 
  686.  
  687. //----------------------------------------------------------------------------------------
  688. // TDescriptor::GetPoint: 
  689. //----------------------------------------------------------------------------------------
  690. Point TDescriptor::GetPoint() const
  691.     {
  692.     Point result;
  693.  
  694.     this->GetBlock((Ptr)&result, sizeof(Point), typeQDPoint);
  695.  
  696.     return result;
  697.     } // TDescriptor::GetPoint 
  698.  
  699. //----------------------------------------------------------------------------------------
  700. // TDescriptor::GetRect: 
  701. //----------------------------------------------------------------------------------------
  702. Rect TDescriptor::GetRect() const
  703.     {
  704.     Rect result;
  705.  
  706.     this->GetBlock((Ptr)&result, sizeof(Rect), typeQDRectangle);
  707.     
  708.     return result;
  709.     } // TDescriptor::GetRect 
  710.  
  711. //----------------------------------------------------------------------------------------
  712. // TDescriptor::GetString: 
  713. //----------------------------------------------------------------------------------------
  714. void TDescriptor::GetString(Str255 result) const
  715.     {
  716.     result[0] = 0;
  717.  
  718.     if(this->DataHandleIsNil())
  719.         FailErr(errAECantSupplyType);
  720.         
  721.     if(this->DescriptorType() == typeChar)
  722.         {
  723.         Size length = GetHandleSize(fDataHandle);
  724.         if(length > 255)
  725.             length = 255;
  726.         BlockMove(*fDataHandle, (Ptr)&result[1], length);
  727.         result[0] = (unsigned char) length;
  728.         }
  729.     else
  730.         {
  731.         TDescriptor makeDataString;
  732.         
  733.         makeDataString = this->Coerce(typeChar);
  734.         ASSERT(makeDataString.DescriptorType() == typeChar);
  735.         makeDataString.GetString(result);
  736.         makeDataString.Dispose();
  737.         }
  738.     } // TDescriptor::GetString 
  739.  
  740. //----------------------------------------------------------------------------------------
  741. // TDescriptor::GetDateTimeRec: 
  742. //----------------------------------------------------------------------------------------
  743. DateTimeRec TDescriptor::GetDateTimeRec() const
  744.     {
  745.     DateTimeRec dateTime;
  746.     
  747.     //
  748.     // We'll do our own coercion from typeLongInteger, if necessary.
  749.     // We should really have a coercion handler for this
  750.     //
  751.     if(this->DescriptorType() == typeLongInteger)
  752.         {
  753.         long secsSince1904 = this->GetLong();
  754.         Secs2Date(secsSince1904,&dateTime);
  755.         }
  756.     else
  757.         {
  758.         //
  759.         // Get the time date rec
  760.         //
  761.         this->GetBlock( (Ptr)&dateTime, sizeof(DateTimeRec), typeDateTimeRec);
  762.         }
  763.     
  764.     return dateTime;
  765.     } // TDescriptor::GetDateTimeRec 
  766.  
  767. //----------------------------------------------------------------------------------------
  768. // TDescriptor::GetFSS: 
  769. //----------------------------------------------------------------------------------------
  770. void TDescriptor::GetFSS(FSSpec& spec) const
  771.     {
  772.     this->GetBlock((Ptr)&spec, sizeof(FSSpec), typeFSS);
  773.     } // TDescriptor::GetFSS 
  774.  
  775. //----------------------------------------------------------------------------------------
  776. // InterpretCompareResult:
  777. //
  778. // Given two keys and a comparison opperator, this function determines if
  779. // the comparison between key2 and key1 is true or false.  key1 and key2 should
  780. // be either two long integers representing the various values of the two descriptors
  781. // being compared, or key1 may be set to 0 and key2 set to -1 (key2 < key1), 0
  782. // (key1 == key2) or 1 (key2 > key1).
  783. //
  784. // This function is used by GeneralCompare, which is used by TDescriptor::Compare
  785. //----------------------------------------------------------------------------------------
  786. Boolean InterpretCompareResult(DescType comparisonOperator, long key1, long key2 )
  787.     {
  788.     switch(comparisonOperator)
  789.         {
  790.         case kAEEquals:
  791.             {
  792.             return key1 == key2;
  793.             }
  794.         
  795.         case kASNotEqual:
  796.             {
  797.             return key1 != key2;
  798.             }
  799.         
  800.         case kAEGreaterThan:
  801.             {
  802.             return key1 > key2;
  803.             }
  804.         
  805.         case kAEGreaterThanEquals:
  806.             {
  807.             return key1 >= key2;
  808.             }
  809.         
  810.         case kAELessThan:
  811.             {
  812.             return key1 < key2;
  813.             }
  814.         
  815.         case kAELessThanEquals:
  816.             {
  817.             return key1 <= key2;
  818.             }
  819.         
  820.         //
  821.         // ••• Perhaps we should fail if we don't recognize the comparisonOperator
  822.         //
  823.         default:
  824.             {
  825.             return false;
  826.             }
  827.         }
  828.     } // InterpretCompareResult 
  829.  
  830. //----------------------------------------------------------------------------------------
  831. // GeneralCompare: 
  832. //
  833. // This is a general comparison routine that works on streams of bytes.  It is assumed
  834. // that the data being compared follows the same ordering rules as strings.  The
  835. // 'caseSensitive' flag should always be true for non-string objects, of course.
  836. //----------------------------------------------------------------------------------------
  837. Boolean GeneralCompare(DescType comparisonOperator, Ptr data, Size length, Ptr compareWith, Size comparisonLength, Boolean caseSensitive)
  838.     {
  839.     Boolean comparisonResult = false;
  840.     long i = 0;
  841.         
  842.     switch(comparisonOperator)
  843.         {
  844.         case kAEEquals:        
  845.         case kASNotEqual:
  846.         case kAEGreaterThan:
  847.         case kAEGreaterThanEquals:
  848.         case kAELessThan:
  849.         case kASLessThanOrEqual:
  850.             {
  851.             short intermediateResult = 0;
  852.             Size max = (length < comparisonLength ? length : comparisonLength);
  853.             
  854.             //
  855.             // We have a little bit of code duplication here
  856.             // to make the code run a little faster
  857.             //
  858.             if(caseSensitive)
  859.                 {
  860.                 for(i=0; i < max; ++i)
  861.                     {
  862.                     if(*((unsigned char*)compareWith) > *((unsigned char*)data))
  863.                         {
  864.                         intermediateResult = 1;
  865.                         break;
  866.                         }
  867.                     else if(*((unsigned char*)compareWith) < *((unsigned char*)data))
  868.                         {
  869.                         intermediateResult = -1;
  870.                         break;
  871.                         }
  872.                     ++compareWith;
  873.                     ++data;
  874.                     }
  875.                 }
  876.             else
  877.                 {
  878.                 for(i=0; i < max; ++i)
  879.                     {
  880.                     unsigned char compareWithChar = *((unsigned char*)compareWith);
  881.                     unsigned char dataChar = *((unsigned char*)data);
  882.                     
  883.                     if((compareWithChar >= 'a') && (compareWithChar <= 'z'))
  884.                         compareWithChar = compareWithChar - 'a' + 'A';
  885.                     if((dataChar >= 'a') && (dataChar <= 'z'))
  886.                         dataChar = dataChar - 'a' + 'A';
  887.                         
  888.                     if(compareWithChar > dataChar)
  889.                         {
  890.                         intermediateResult = 1;
  891.                         break;
  892.                         }
  893.                     else if(compareWithChar < dataChar)
  894.                         {
  895.                         intermediateResult = -1;
  896.                         break;
  897.                         }
  898.                     ++compareWith;
  899.                     ++data;
  900.                     }
  901.                 }
  902.             
  903.             if(intermediateResult == 0)
  904.                 intermediateResult = (comparisonLength > length) - (comparisonLength < length);
  905.             
  906.             comparisonResult = InterpretCompareResult(comparisonOperator,0,intermediateResult);
  907.             
  908.             break;
  909.             }
  910.         
  911.         case kAEBeginsWith:
  912.             {
  913.             comparisonResult = GeneralCompare(kAEEquals, data, comparisonLength, compareWith, comparisonLength,caseSensitive);
  914.             break;
  915.             }
  916.             
  917.         case kAEEndsWith:
  918.             {
  919.             i = (length - comparisonLength);
  920.             if(i >= 0)
  921.                 comparisonResult = GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive);
  922.             break;
  923.             }
  924.             
  925.         case kAEContains:
  926.             {
  927.             for(i=0;i<=length - comparisonLength;++i)
  928.                 {
  929.                 if(GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive))
  930.                     {
  931.                     comparisonResult = true;
  932.                     break;
  933.                     }
  934.                 }
  935.             
  936.             break;
  937.             }
  938.             
  939.         default:
  940.             {
  941.             comparisonResult = false;
  942.             }
  943.         }
  944.     
  945.     return comparisonResult;
  946.     } // GeneralCompare 
  947.  
  948.  
  949. //----------------------------------------------------------------------------------------
  950. // StringContains: 
  951. //----------------------------------------------------------------------------------------
  952. /*Boolean    StringContains(Str255 thisString, Str255 withString)
  953.     {
  954.     unsigned char thisSize = (unsigned char)thisString[0];
  955.     unsigned char withSize = (unsigned char)withString[0];
  956.  
  957.     if ((thisSize == 0) || (withSize > thisSize))        // quick check
  958.         return false;
  959.  
  960.     Boolean b = false;
  961.     unsigned char* a = &thisString[0];
  962.     unsigned char* last = a + thisSize - withSize + 1;
  963.     do
  964.         {
  965.         b = IUMagIDString(Ptr(++a), Ptr(withString[1]), withSize, withSize);
  966.         }
  967.     while (b && (a < last));
  968.  
  969.     return (b == false);
  970.     } // StringContains */
  971.  
  972. //----------------------------------------------------------------------------------------
  973. // TDescriptor::Compare: 
  974. //----------------------------------------------------------------------------------------
  975. Boolean TDescriptor::Compare(DescType comparisonOperator, Str255 withString) const
  976.     {
  977.     Str255 thisString;
  978.     Size thisSize;
  979.     Size withSize;
  980.     Boolean compareResult = false;
  981.     
  982.     //
  983.     // Fetch a copy of 'thisString' (which we will freely destroy later)
  984.     //
  985.     this->GetString(thisString);
  986.     thisSize = (unsigned char)thisString[0];
  987.     withSize = (unsigned char)withString[0];
  988.  
  989.     switch(comparisonOperator)
  990.         {
  991.         //
  992.         // Check to see if we can find the string anywhere inside
  993.         //
  994.         case kAEContains:
  995.             {
  996.             long    i;
  997.             
  998.             unsigned char* a = &thisString[0];
  999.             for(i=0;i<thisSize - withSize + 1;++i)
  1000.                 {
  1001.                 *a = (unsigned char)withSize;
  1002.                 compareResult = (IUEqualString(a, withString) == 0);
  1003.                 if(compareResult == true)
  1004.                     break;
  1005.                 ++a;
  1006.                 }
  1007.             }
  1008.             break;
  1009.         
  1010.         //
  1011.         // Relational tests are easy:  use IUCompString
  1012.         //
  1013.         case kAEGreaterThan:
  1014.         case kAEGreaterThanEquals:
  1015.         case kAELessThan:
  1016.         case kASLessThanOrEqual:
  1017.             {
  1018.             compareResult = InterpretCompareResult(comparisonOperator, IUCompString(thisString, withString), 0);
  1019.             }
  1020.             break;
  1021.         
  1022.         //
  1023.         // For AEEndsWith, move the end of the string down to
  1024.         // the beginning of the string, then fall through to
  1025.         // the 'begins with' case
  1026.         //
  1027.         // International allert:  this could clip a two-byte
  1028.         // character in half, but doing so probably won't cause
  1029.         // a problem, since we are looking for exact matches.
  1030.         //
  1031.         case kAEEndsWith:
  1032.             {
  1033.             if(withSize <= thisSize)
  1034.                 BlockMove((Ptr)&thisString[thisSize - withSize + 1],(Ptr)&thisString[1],withSize);
  1035.             }
  1036.             // !!! fall through
  1037.             
  1038.         //
  1039.         // For kAEBeginsWith, set the length of the 'thisString'
  1040.         // to the length of the 'withString' and do an equality test
  1041.         //
  1042.         // International allert:  this could clip a two-byte
  1043.         // character in half, but doing so probably won't cause
  1044.         // a problem, since we are looking for exact matches.
  1045.         //
  1046.         case kAEBeginsWith:
  1047.             {
  1048.             thisString[0] = (unsigned char)withSize;
  1049.             }
  1050.             // !!! fall through...
  1051.         
  1052.         //
  1053.         // kAEEquals and kASNotEqual must come immediately after
  1054.         // begins with and ends with
  1055.         //
  1056.         case kAEEquals:
  1057.         case kASNotEqual:
  1058.             {
  1059.             compareResult = (IUEqualString(thisString, withString) == 0);
  1060.             if(comparisonOperator == kASNotEqual)
  1061.                 compareResult = !compareResult;
  1062.             }
  1063.             break;
  1064.         
  1065.         //
  1066.         // Shouldn't ever get here...
  1067.         //
  1068.         default:
  1069.             {
  1070.             compareResult = GeneralCompare(comparisonOperator,(Ptr)&thisString[1],thisSize,(Ptr)&withString[1],withSize,false);
  1071.             }
  1072.             break;
  1073.         }
  1074.     
  1075.     return compareResult;
  1076.     } // TDescriptor::Compare 
  1077.  
  1078. //----------------------------------------------------------------------------------------
  1079. // TDescriptor::Compare: 
  1080. //
  1081. // Compare two descriptors.  ComparisonOperator should be one of the following:
  1082. //
  1083. // kAEEquals, kASNotEqual, kAEGreaterThan, kAEGreaterThanEquals, kAELessThan,
  1084. // kASLessThanOrEqual, kAEBeginsWith, kAEEndsWith, or kAEContains
  1085. //----------------------------------------------------------------------------------------
  1086. Boolean TDescriptor::Compare(DescType comparisonOperator, TDescriptor& compareWith) const
  1087.     {
  1088.     Boolean compareResult = false;
  1089.     
  1090.     //
  1091.     // It might be nice to try to do a type coercion here, but for now
  1092.     // we only compare descriptors of the same type
  1093.     //
  1094.     if(this->DescriptorType() != compareWith.DescriptorType())
  1095.         FailErr(errAEEventNotHandled);
  1096.     
  1097.     switch(this->DescriptorType())
  1098.         {
  1099.         case typeChar:
  1100.             {
  1101.             Str255 withString;
  1102.  
  1103.             compareWith.GetString(withString);
  1104.             compareResult = this->Compare(comparisonOperator, withString);
  1105.  
  1106.             break;
  1107.             }
  1108.             break;
  1109.         
  1110.         //
  1111.         // We convert DateTimeRecs into integers for comparison so that
  1112.         // someone can supply "the 300th day of January", and it will compare
  1113.         // as being larger than "the 2nd day of February".
  1114.         //
  1115.         // Begins with, ends with and contains are meaningless for dates, though.
  1116.         //
  1117.         case typeLongInteger:
  1118.         case typeDateTimeRec:
  1119.             {            
  1120.             compareResult = InterpretCompareResult(comparisonOperator, this->GetLong(), compareWith.GetLong() );
  1121.             }
  1122.             break;
  1123.         
  1124.         //
  1125.         // If we don't know what type this is, we'll do our best
  1126.         // to do a generic comparison.  This can result in some
  1127.         // very stupid comparisons, but that's life.
  1128.         //
  1129.         default:
  1130.             {
  1131.             Handle        withHandle = compareWith.DataHandle();
  1132.             short        thisState;
  1133.             short        withState;
  1134.             Size        thisSize;
  1135.             Size        withSize;
  1136.             
  1137.             thisState = HGetState(fDataHandle);
  1138.             withState = HGetState(withHandle);
  1139.             thisSize = GetHandleSize(fDataHandle);
  1140.             withSize = GetHandleSize(withHandle);
  1141.             
  1142.             compareResult = GeneralCompare(comparisonOperator,(Ptr)*fDataHandle,thisSize,(Ptr)*withHandle,withSize,true);
  1143.             
  1144.             HSetState(fDataHandle,thisState);
  1145.             HSetState(withHandle,withState);
  1146.             }
  1147.             break;
  1148.         }
  1149.         
  1150.     return compareResult;
  1151.     } // TDescriptor::Compare
  1152.  
  1153. //========================================================================================
  1154. // CLASS TDescriptorLoop
  1155. //
  1156. // The class TDescriptorLoop is used by the macro FOREACHDESCRIPTOR.  Note that the
  1157. // descriptor returned by "Next" is a copy that must be disposed of by the programmer.
  1158. //
  1159. // We could have TDescriptorLoop keep track of the descriptor it created, and have it
  1160. // dispose it when done.  This would necessitate an 'orphan' method, though, in case
  1161. // someone else wanted to adopt the descriptor.
  1162. //========================================================================================
  1163.  
  1164. //----------------------------------------------------------------------------------------
  1165. // TDescriptorLoop::Next: 
  1166. //
  1167. // If 'key' is not nil, it is filled in with the keyword from the i'th item of the
  1168. // list (if the list is a record)
  1169. //
  1170. // If 'dataHandle' is not nil, it is filled in with the data handle from the i'th
  1171. // item of the list.  This is only done to be nice to the FOREACHTOKEN macro.
  1172. //----------------------------------------------------------------------------------------
  1173. Boolean TDescriptorLoop::Next(TDescriptor& d, AEKeyword* key, Handle* dataHandle)
  1174.     {
  1175.     Boolean moreToDo = false;
  1176.     
  1177.     //
  1178.     // Set up on the first time through the loop
  1179.     //
  1180.     if(fIndex == 0)
  1181.         {
  1182.         fCount = fDescriptorList->CountItems();
  1183.         if(d.IsNullDescriptor() == false)
  1184.             {
  1185.             DebugStr("\pTDescriptorLoop::Next:  'd' was not null on first iteration!");
  1186.             FailErr(errAEEventFailed);
  1187.             }
  1188.         }
  1189.  
  1190.     //
  1191.     // Advance to the next item in the list...
  1192.     //
  1193.     fIndex++;
  1194.     
  1195.     //
  1196.     // Dispose of the 'd' from last time through the loop
  1197.     //
  1198.     d.Dispose();
  1199.     
  1200.     //
  1201.     // Are there still items in the list?
  1202.     //
  1203.     if (fIndex <= fCount)
  1204.         {
  1205.         //
  1206.         // At this point, we could check to see if 'fDescriptorList' actually
  1207.         // points to something that is _not_ a list; if so, we coule return a
  1208.         // _reference_ to the single object, and set a field that indicates that
  1209.         // 'd' is a reference, and should not be disposed next time through the
  1210.         // loop.  The reason we do not do this is that 'd' will be disposed by
  1211.         // the client code if there is a failure, and there is no good way for
  1212.         // the client to know if d is a reference or not.  We could remember
  1213.         // what 'd' was and clean it up in our destructor, but failures can
  1214.         // cause our TDescriptorLoop object to be orphaned without ever being
  1215.         // destructed.
  1216.         //
  1217.         d = fDescriptorList->GetNthDescriptor(fIndex, typeWildCard, key);
  1218.         
  1219.         moreToDo = true;
  1220.         }
  1221.     //
  1222.     // No more items, clean up
  1223.     //
  1224.     else
  1225.         {
  1226.         if(key != nil)
  1227.             *key = typeNull;
  1228.         d.MakeNull();
  1229.         }
  1230.     
  1231.     //
  1232.     // Fill in the 'dataHandle' parameter if it was passed in.
  1233.     // (We only do this to make life easy for the FOREACHTOKEN macro)
  1234.     //
  1235.     if(dataHandle != nil)
  1236.         *dataHandle = d.DataHandle();
  1237.     
  1238.     return moreToDo;
  1239.     } // TDescriptorLoop::Next 
  1240.  
  1241.  
  1242. //----------------------------------------------------------------------------------------
  1243. // TDescriptor::MakeEmptyList:
  1244. //
  1245. // Make an empty descriptor list.  It is usually not necessary to make an empty list,
  1246. // because all of the TDescriptor routines will interpret null descriptors as
  1247. // empty lists.  Sometimes it is necessary to return an empty list as the result of
  1248. // an AppleEvent handler, though, and in this case a null descriptor is _not_ equivalent.
  1249. //
  1250. // By default, include no factored data and make an AEList.
  1251. //----------------------------------------------------------------------------------------
  1252. void TDescriptor::MakeEmptyList()
  1253.     {
  1254.     this->CreateList(kMakeAEList);
  1255.     } // TDescriptor::MakeEmptyList 
  1256.  
  1257. //----------------------------------------------------------------------------------------
  1258. // TDescriptor::MakeList: 
  1259. //
  1260. // If this descriptor is null, an empty list is created.  If this descriptor is not
  1261. // empty, then a list is created and this descriptor is placed inside it.  If this
  1262. // descriptor is already a list, then no action is taken.
  1263. //
  1264. // ••• DANGER:  Does a coerce-in-place!
  1265. //----------------------------------------------------------------------------------------
  1266. void TDescriptor::MakeList()
  1267.     {
  1268.     if(this->IsNullDescriptor())
  1269.         {
  1270.         this->CreateList();
  1271.         }
  1272.     else if(this->DescriptorType() != typeAEList)
  1273.         {
  1274.         this->CoerceInPlace(typeAEList);
  1275.         }
  1276.     } // TDescriptor::MakeList 
  1277.     
  1278. //----------------------------------------------------------------------------------------
  1279. // TDescriptor::CountItems:
  1280. //
  1281. // Count the items in a descriptor list. If this descriptor is not of typeAEList, then it
  1282. // only has one item, and if the descriptor is null, then it has no items.
  1283. //----------------------------------------------------------------------------------------
  1284. long TDescriptor::CountItems() const
  1285.     {
  1286.     long items = 1;
  1287.     if(this->IsNullDescriptor())
  1288.         items = 0;
  1289.     else if((this->DescriptorType() == typeAEList) || (this->DescriptorType() == typeAERecord))
  1290.         FailErr(AECountItems(*this, &items));
  1291.     return items;
  1292.     } // TDescriptor::CountItems 
  1293.  
  1294. //----------------------------------------------------------------------------------------
  1295. // TDescriptor::GetNthDescriptor:
  1296. //
  1297. // Get the indexed descriptor from an event.  This method will fail if given an index
  1298. // less than one or greater than the count returned by TDescriptor::CountItems.
  1299. // The descriptor returned is _always_ a copy that must be disposed of with
  1300. // TDescriptor::Dispose.
  1301. //----------------------------------------------------------------------------------------
  1302. TDescriptor TDescriptor::GetNthDescriptor(long index, DescType desiredType, AEKeyword* key) const
  1303.     {
  1304.     TDescriptor descriptor;
  1305.     AEKeyword ignoreKey;
  1306.     
  1307.     if(key == nil)
  1308.         key = &ignoreKey;
  1309.         
  1310.     //
  1311.     // We can "GetNthDescriptor" on an item that is not of typeAEList
  1312.     // if the index is one; we do this by cloning ourself
  1313.     // (n.b. AERecords are also lists)
  1314.     //
  1315.     if((DescriptorType() != typeAEList) && (DescriptorType() != typeAERecord))
  1316.         {
  1317.         if(index != 1)
  1318.             FailErr(-1);        // ••• index out of range
  1319.         
  1320.         *key = typeWildCard; 
  1321.         descriptor = this->Clone();
  1322.         }
  1323.     else
  1324.         {
  1325.         FailErr(AEGetNthDesc(*this, index, desiredType, key, descriptor));
  1326.         }
  1327.     
  1328.     return descriptor;
  1329.     } // TDescriptor::GetNthDescriptor 
  1330.  
  1331. //----------------------------------------------------------------------------------------
  1332. // TDescriptor::AddDescriptor:
  1333. //
  1334. // Add data to a descriptor list at a specified index, replacing any item already stored
  1335. // at that position.
  1336. //----------------------------------------------------------------------------------------
  1337. void TDescriptor::AddDescriptor(long index, TDescriptor& data)
  1338.     {
  1339.     //
  1340.     // If the list is completely empty, just put the data directly into
  1341.     // this descriptor (don't make a list)
  1342.     //
  1343.     if(this->IsNullDescriptor())
  1344.         {
  1345.         this->CopyDesc(data);
  1346.         }
  1347.     else
  1348.         {
  1349.         // If we're not a list yet, we'd better make ourselves one now.
  1350.         if(this->DescriptorType() != typeAEList)
  1351.             this->MakeList();
  1352.         FailErr(AEPutDesc(*this, index, data));
  1353.         }
  1354.     } // TDescriptor::AddDescriptor 
  1355.  
  1356. //----------------------------------------------------------------------------------------
  1357. // TDescriptor::AddDescriptor:
  1358. //
  1359. // Add data to a descriptor list at the end of the list
  1360. //----------------------------------------------------------------------------------------
  1361. void TDescriptor::AddDescriptor(TDescriptor& data)
  1362.     {
  1363.     this->AddDescriptor(0,data);
  1364.     } // TDescriptor::AddDescriptor 
  1365.  
  1366. //----------------------------------------------------------------------------------------
  1367. // TDescriptor::AddData: 
  1368. //----------------------------------------------------------------------------------------
  1369. void TDescriptor::AddData(long index, DescType descType, Ptr data, Size length)
  1370.     {
  1371.     //
  1372.     // If the list is completely empty, we'd better make an empty list
  1373.     // (the type coercion from null to typeAEList probably works,
  1374.     // but I have not tested it yet; the following two lines may
  1375.     // be superfluous)
  1376.     //
  1377.     if(this->IsNullDescriptor())
  1378.         this->MakeEmptyList();
  1379.     
  1380.     //
  1381.     // If we're not a list yet, we'd better make ourselves one now.
  1382.     //
  1383.     if(this->DescriptorType() != typeAEList)
  1384.         this->CoerceInPlace(typeAEList);
  1385.     
  1386.     //
  1387.     // Put the data into the list
  1388.     //
  1389.     FailErr(AEPutPtr(*this,index,descType,data,length));
  1390.     } // TDescriptor::AddData 
  1391.  
  1392. //----------------------------------------------------------------------------------------
  1393. // TDescriptor::AddData: 
  1394. //----------------------------------------------------------------------------------------
  1395. void TDescriptor::AddData(DescType descType, Ptr data, Size length)
  1396.     {
  1397.     this->AddData(0,descType,data,length);
  1398.     } // TDescriptor::AddData 
  1399.  
  1400. //----------------------------------------------------------------------------------------
  1401. // TDescriptor::AddLong: 
  1402. //----------------------------------------------------------------------------------------
  1403. void TDescriptor::AddLong(long number)
  1404.     {
  1405.     this->AddData(typeLongInteger,(Ptr)&number,sizeof(long));
  1406.     } // TDescriptor::AddLong 
  1407.  
  1408. //----------------------------------------------------------------------------------------
  1409. // TDescriptor::AddType: 
  1410. //----------------------------------------------------------------------------------------
  1411. void TDescriptor::AddType(DescType descType)
  1412.     {
  1413.     this->AddData(typeType,(Ptr)&descType,sizeof(DescType));
  1414.     } // TDescriptor::AddType 
  1415.  
  1416. //----------------------------------------------------------------------------------------
  1417. // TDescriptor::AppendList:
  1418. //
  1419. // Append a list onto the end of this one.  The list passed in may be a null descriptor
  1420. // or a single item as well as a list.
  1421. //----------------------------------------------------------------------------------------
  1422. void TDescriptor::AppendList(const TDescriptor& list)
  1423.     {
  1424.     TDescriptor descriptor;
  1425.     OSErr err = noErr;
  1426.     
  1427.     //
  1428.     // If this descriptor is a null descriptor, then we just want
  1429.     // to copy the incoming list.
  1430.     //
  1431.     // In the past we did not do this check, which resulted in
  1432.     // the unfortunate side effect of converting a single-item
  1433.     // list into a single (non-list) descriptor whenever said
  1434.     // list was 'AppendList'ed into an empty list.  While this
  1435.     // may be more efficient, it really hosed us over in the case
  1436.     // of GetData on the selection property, which is SUPPOSED
  1437.     // to return a single-item list (as opposed to a single
  1438.     // descriptor) if there is only one item in the list.  (This
  1439.     // is quite different from most other objects, which are
  1440.     // supposed to return single descriptors instead of single-
  1441.     // item lists whenever there is only one object in the result.)
  1442.     //
  1443.     if(this->IsNullDescriptor())
  1444.         {
  1445.         this->CopyDesc(list);
  1446.         }
  1447.     else if(list.IsNullDescriptor() == false)
  1448.         {
  1449.         Try
  1450.             {
  1451.             FOREACHDESCRIPTOR(&list, descriptor)
  1452.                 {
  1453.                 this->AddDescriptor(descriptor);
  1454.                 }
  1455.             }
  1456.         Catch(err)
  1457.             {
  1458.             descriptor.Dispose();
  1459.             Throw(err);
  1460.             }
  1461.         }
  1462.     } // TDescriptor::AppendList 
  1463.  
  1464. //----------------------------------------------------------------------------------------
  1465. // TDescriptor::AdoptList: 
  1466. //----------------------------------------------------------------------------------------
  1467. void TDescriptor::AdoptList(TDescriptor* list)
  1468.     {
  1469.     if(this->IsNullDescriptor())
  1470.         {
  1471.         this->AdoptDesc(*list);
  1472.         }
  1473.     else
  1474.         {
  1475.         this->AppendList(*list);
  1476.         list->Dispose();
  1477.         }
  1478.     } // TDescriptor::AdoptList 
  1479.  
  1480. //----------------------------------------------------------------------------------------
  1481. // TDescriptor::MakeAERecord:
  1482. //
  1483. // CreateList creates both AERecords and AELists.
  1484. //----------------------------------------------------------------------------------------
  1485. void TDescriptor::MakeAERecord()
  1486.     {
  1487.     this->CreateList(kMakeAERecord);
  1488.     } // TDescriptor::MakeAERecord 
  1489.     
  1490. //----------------------------------------------------------------------------------------
  1491. // TDescriptor::GetDescriptor:
  1492. //
  1493. // Get the ae descriptor from the event. If the desired type is not specified, it
  1494. // defaults to typeWildCard
  1495. //----------------------------------------------------------------------------------------
  1496. TDescriptor TDescriptor::GetDescriptor(AEKeyword key, DescType desiredType)
  1497.     {
  1498.     TDescriptor result;
  1499.  
  1500.     //
  1501.     // n.b. This object must be typeAERecord or typeAppleEvent, or this
  1502.     // call will fail.  Other record-like descriptors (e.g. object specifiers)
  1503.     // cannot be passed to AEGetParamDesc.
  1504.     //
  1505.     FailErr(AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result));
  1506.     
  1507.     return result;
  1508.     } // TDescriptor::GetDescriptor 
  1509.     
  1510. //----------------------------------------------------------------------------------------
  1511. // TDescriptor::GetOptionalParameter:
  1512. //
  1513. // Like 'GetDescriptor, but returns a null descriptor if the specified parameter could not
  1514. // be extracted.
  1515. //----------------------------------------------------------------------------------------
  1516. TDescriptor TDescriptor::GetOptionalParameter(AEKeyword key, DescType desiredType)
  1517.     {
  1518.     TDescriptor result;
  1519.     OSErr err = noErr;
  1520.  
  1521.     //
  1522.     // It's probably not necessary to call MakeNull if there is
  1523.     // an error, but we might as well be safe (paranoid?).
  1524.     //
  1525.     err = AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result);
  1526.     if(err != noErr)
  1527.         result.MakeNull();
  1528.     
  1529.     return result;
  1530.     } // TDescriptor::GetOptionalParameter 
  1531.  
  1532. //----------------------------------------------------------------------------------------
  1533. // TDescriptor::GetParameterPtr:
  1534. //
  1535. // Get the ae descriptor from the record
  1536. //----------------------------------------------------------------------------------------
  1537. void TDescriptor::GetParameterPtr(AEKeyword key, DescType desiredType, DescType *typeCode, Ptr dataPtr, Size maximumSize, Size *actualSize)
  1538.     {
  1539.     //
  1540.     // n.b. This object must be typeAERecord or typeAppleEvent, or this
  1541.     // call will fail.  Other record-like descriptors (e.g. object specifiers)
  1542.     // cannot be passed to AEGetParamPtr.
  1543.     //
  1544.     FailErr(AEGetParamPtr(*this, key, desiredType, typeCode, dataPtr, maximumSize, actualSize));
  1545.     } // TDescriptor::GetParameterPtr 
  1546.     
  1547. //----------------------------------------------------------------------------------------
  1548. // TDescriptor::GetLongParameter:
  1549. //
  1550. // Get the first longword of data from a parameter coerced to the specified type
  1551. // (usually typeLongInteger)
  1552. //----------------------------------------------------------------------------------------
  1553. long TDescriptor::GetLongParameter(AEKeyword key, DescType desiredType)
  1554.     {
  1555.     long actualSize;
  1556.     DescType typeCode;
  1557.     long result = 0;
  1558.     GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(long), &actualSize);
  1559.     
  1560.     return result;
  1561.     } // TDescriptor::GetLongParameter 
  1562.     
  1563. //----------------------------------------------------------------------------------------
  1564. // TDescriptor::GetShortParameter:
  1565. //
  1566. // Get the first shortword of data from a parameter coerced to the specified type
  1567. // (usually typeShortInteger)
  1568. //----------------------------------------------------------------------------------------
  1569. short TDescriptor::GetShortParameter(AEKeyword key, DescType desiredType)
  1570.     {
  1571.     long actualSize;
  1572.     DescType typeCode;
  1573.     short result = 0;
  1574.     GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(short), &actualSize);
  1575.     
  1576.     return result;
  1577.     } // TDescriptor::GetShortParameter 
  1578.     
  1579. //----------------------------------------------------------------------------------------
  1580. // TDescriptor::GetDirectObject:
  1581. //
  1582. // Get the direct object of the event
  1583. //----------------------------------------------------------------------------------------
  1584. TDescriptor TDescriptor::GetDirectObject()
  1585.     {
  1586.     return GetDescriptor(keyDirectObject);
  1587.     } // TDescriptor::GetDirectObject 
  1588.  
  1589. //----------------------------------------------------------------------------------------
  1590. // TDescriptor::GetErrorCode:
  1591. //
  1592. // Get an error code
  1593. //----------------------------------------------------------------------------------------
  1594. long TDescriptor::GetErrorCode()
  1595.     {
  1596.     return GetLongParameter(keyErrorNumber);
  1597.     } // TDescriptor::GetErrorCode 
  1598.  
  1599. //----------------------------------------------------------------------------------------
  1600. // TDescriptor::PutDescriptor:
  1601. //
  1602. // Put a TDescriptor into the event
  1603. //----------------------------------------------------------------------------------------
  1604. void TDescriptor::PutDescriptor(AEKeyword key, TDescriptor data)
  1605.     {
  1606.     FailErr(AEPutParamDesc(*this, key, data));
  1607.     } // TDescriptor::PutDescriptor 
  1608.     
  1609. //----------------------------------------------------------------------------------------
  1610. // TDescriptor::PutParameterPtr:
  1611. //
  1612. // Create a descriptor from a block of data and insert it into the record
  1613. //----------------------------------------------------------------------------------------
  1614. void TDescriptor::PutParameterPtr(AEKeyword key, DescType typeCode, Ptr dataPtr, Size dataSize)
  1615.     {
  1616.     FailErr(AEPutParamPtr(*this, key, typeCode, dataPtr, dataSize));
  1617.     } // TDescriptor::PutParameterPtr 
  1618.  
  1619. //----------------------------------------------------------------------------------------
  1620. // TDescriptor::PutParameterHandle: 
  1621. //----------------------------------------------------------------------------------------
  1622. void TDescriptor::PutParameterHandle(AEKeyword key, DescType typeCode, Handle dataHandle)
  1623.     {
  1624.     short        handleState;
  1625.     Size        dataSize;
  1626.     
  1627.     //
  1628.     // Feature:  if the dataHandle is nil, nothing is added to the AERecord.
  1629.     //
  1630.     if(dataHandle != nil)
  1631.         {
  1632.         handleState = HGetState(dataHandle);
  1633.         HLock(dataHandle);
  1634.         dataSize = GetHandleSize(dataHandle);
  1635.         
  1636.         this->PutParameterPtr(key,typeCode,*dataHandle,dataSize);
  1637.         
  1638.         HSetState(dataHandle,handleState);
  1639.         }
  1640.     } // TDescriptor::PutParameterHandle 
  1641.     
  1642. //----------------------------------------------------------------------------------------
  1643. // TDescriptor::PutLongParameter:
  1644. //
  1645. // Put a long parameter (type specified)
  1646. //----------------------------------------------------------------------------------------
  1647. void TDescriptor::PutLongParameter(AEKeyword key, DescType typeCode, long data)
  1648.     {
  1649.     this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(long));
  1650.     } // TDescriptor::PutLongParameter 
  1651.     
  1652. //----------------------------------------------------------------------------------------
  1653. // TDescriptor::PutLongParameter:
  1654. //
  1655. // Put a long parameter (type is 'typeLongInteger', the most common case)
  1656. //----------------------------------------------------------------------------------------
  1657. void TDescriptor::PutLongParameter(AEKeyword key, long data)
  1658.     {
  1659.     this->PutLongParameter(key,typeLongInteger,data);
  1660.     } // TDescriptor::PutLongParameter 
  1661.     
  1662. //----------------------------------------------------------------------------------------
  1663. // TDescriptor::PutShortParameter:
  1664. //
  1665. // Put a short parameter (type specified)
  1666. //----------------------------------------------------------------------------------------
  1667. void TDescriptor::PutShortParameter(AEKeyword key, DescType typeCode, short data)
  1668.     {
  1669.     this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(short));
  1670.     } // TDescriptor::PutShortParameter 
  1671.     
  1672. //----------------------------------------------------------------------------------------
  1673. // TDescriptor::PutShortParameter:
  1674. //
  1675. // Put a short parameter (type is 'typeShortInteger', the most common case)
  1676. //----------------------------------------------------------------------------------------
  1677. void TDescriptor::PutShortParameter(AEKeyword key, short data)
  1678.     {
  1679.     this->PutShortParameter(key,typeShortInteger,data);
  1680.     } // TDescriptor::PutShortParameter 
  1681.  
  1682. //----------------------------------------------------------------------------------------
  1683. // TDescriptor::PutResult: 
  1684. //
  1685. // Put the provided descriptor into the result parameter of this event.  If the data
  1686. // is a null descriptor, then put in an empty list instead.
  1687. //----------------------------------------------------------------------------------------
  1688. void TDescriptor::PutResult(TDescriptor data)
  1689.     {
  1690.     OSErr err = noErr;
  1691.     
  1692.     //
  1693.     // If there's nothing in the data, then insert an empty list.
  1694.     //
  1695.     if(data.IsNullDescriptor())
  1696.         {
  1697.         TDescriptor emptyList;
  1698.  
  1699.         Try
  1700.             {
  1701.             emptyList.MakeEmptyList();
  1702.             this->PutDescriptor(keyAEResult, emptyList);
  1703.             emptyList.Dispose();
  1704.             }
  1705.         Catch(err)
  1706.             {
  1707.             emptyList.Dispose();
  1708.             Throw(err);
  1709.             }
  1710.         }
  1711.     else
  1712.         {
  1713.         this->PutDescriptor(keyAEResult,data);
  1714.         }
  1715.     } // TDescriptor::PutResult 
  1716.     
  1717. //----------------------------------------------------------------------------------------
  1718. // TDescriptor::PutErrorCode:
  1719. //
  1720. // Put an error code
  1721. //----------------------------------------------------------------------------------------
  1722. void TDescriptor::PutErrorCode(long theErr)
  1723.     {
  1724.     this->PutLongParameter(keyErrorNumber,theErr);
  1725.     } // TDescriptor::PutErrorCode 
  1726.  
  1727. //----------------------------------------------------------------------------------------
  1728. // TDescriptor::Resolve: 
  1729. //----------------------------------------------------------------------------------------
  1730. TTokenDescriptor TDescriptor::Resolve()
  1731.     {
  1732.     return TDescriptor::Resolve(fCallbackFlags);
  1733.     } // TDescriptor::Resolve 
  1734.  
  1735. //----------------------------------------------------------------------------------------
  1736. // TDescriptor::Resolve:
  1737. //
  1738. // Resolves a list of object specifiers into a list of tokens.  A null descriptor will
  1739. // resolve to a token to the null container.
  1740. //
  1741. // n.b. AEResolve will return an error if you pass it a null descriptor; this is why
  1742. //        we include 'magic' checking for null descriptors here.
  1743. //----------------------------------------------------------------------------------------
  1744. TTokenDescriptor TDescriptor::Resolve(short callbackFlags)
  1745.     {
  1746.     TTokenDescriptor resolvedToken;
  1747.     TTokenDescriptor intermediate;
  1748.     TDescriptor descriptor;
  1749.     
  1750.     //
  1751.     // First:  special checking for null descriptors
  1752.     //
  1753.     if(this->IsNullDescriptor())
  1754.         {
  1755.         resolvedToken = CreateNullContainerToken();
  1756.         }
  1757.     //
  1758.     // Next, process non-lists
  1759.     //
  1760.     else if(this->DescriptorType() != typeAEList)
  1761.         {
  1762.         //
  1763.         // If a pre-resolve proc was installed, then call it.
  1764.         //
  1765.         // The Scriptable Finder uses this for resolving token
  1766.         // types that AEResolve does not recognize (e.g. alias
  1767.         // records)
  1768.         //
  1769.         if(gPreResolveProc != nil)
  1770.             {
  1771.             resolvedToken = (*gPreResolveProc)(*this);
  1772.             }
  1773.  
  1774.         //
  1775.         // If the pre-resolve proc did not resolve the token,
  1776.         // then call AEResolve
  1777.         //
  1778.         if(resolvedToken.IsNullDescriptor())
  1779.             FailErr(AEResolve(*this, callbackFlags, resolvedToken));
  1780.         }
  1781.     //
  1782.     // If we have a list, try to resolve each element of the list in turn
  1783.     //
  1784.     else
  1785.         {
  1786.         OSErr err = noErr;
  1787.         
  1788.         Try
  1789.             {
  1790.             FOREACHDESCRIPTOR(this, descriptor)
  1791.                 {
  1792.                 //
  1793.                 // We do not want to dispose of the intermediate token descriptor
  1794.                 // because its data is adopted by the 'result' token descriptor.
  1795.                 //
  1796.                 intermediate = descriptor.Resolve(callbackFlags);
  1797.                 resolvedToken.AdoptToken(intermediate);
  1798.                 intermediate.MakeNull();
  1799.                 }
  1800.             }
  1801.         Catch(err)
  1802.             {
  1803.             descriptor.Dispose();
  1804.             intermediate.DisposeToken();
  1805.             resolvedToken.DisposeToken();
  1806.             Throw(err);
  1807.             }
  1808.         }
  1809.     
  1810.     return resolvedToken;
  1811.     } // TDescriptor::Resolve 
  1812.  
  1813.  
  1814. //========================================================================================
  1815. // CLASS TAEvent
  1816. //
  1817. // AppleEvents are just like AERecords, but they can contain attributes as well as
  1818. // parameters.
  1819. //========================================================================================
  1820.  
  1821.  
  1822. //----------------------------------------------------------------------------------------
  1823. // TAEvent::TAEvent: 
  1824. //----------------------------------------------------------------------------------------
  1825. TAEvent::TAEvent()
  1826.     {
  1827.  
  1828.     } // TAEvent::TAEvent 
  1829.  
  1830.  
  1831. //----------------------------------------------------------------------------------------
  1832. // TAEvent::MakeAppleEvent: 
  1833. //----------------------------------------------------------------------------------------
  1834. void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
  1835.                         const TDescriptor& target, short returnID, long transactionID)
  1836.     {
  1837.     FailErr(AECreateAppleEvent(eventClass, eventID,
  1838.                         (const AEAddressDesc *) &target, returnID, transactionID, *this));
  1839.     } // TAEvent::MakeAppleEvent 
  1840.  
  1841. //----------------------------------------------------------------------------------------
  1842. // TAEvent::MakeAppleEvent: 
  1843. //----------------------------------------------------------------------------------------
  1844. void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
  1845.                         const ProcessSerialNumber& psn, short returnID, long transactionID)
  1846.     {
  1847.     TDescriptor address;
  1848.     address.CopyData(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber));
  1849.     
  1850.     this->MakeAppleEvent(eventClass, eventID, address, returnID, transactionID);
  1851.     
  1852.     address.Dispose();
  1853.     } // TAEvent::MakeAppleEvent 
  1854.  
  1855.  
  1856. #define kCheckAEM            0
  1857. #define kDontUseSelfSend    1
  1858. #define kSelfSendSafe        2
  1859.  
  1860. short gCanUseSelfSend = kCheckAEM;
  1861.  
  1862. //----------------------------------------------------------------------------------------
  1863. // TAEvent::MakeEventAddressedToSelf: 
  1864. //----------------------------------------------------------------------------------------
  1865. void TAEvent::MakeEventAddressedToSelf(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
  1866.     {
  1867.     ProcessSerialNumber current;        // create psn for the current process
  1868.     current.highLongOfPSN = 0;
  1869.     current.lowLongOfPSN = kCurrentProcess;
  1870.     
  1871.     //
  1872.     // Old versions of the AEM leak memory if send-to-self is used
  1873.     //
  1874.     if(gCanUseSelfSend == kCheckAEM)
  1875.         {
  1876.         long aevtSelector = 0;
  1877.         OSErr err = Gestalt('evnt', &aevtSelector);
  1878.         gCanUseSelfSend = ((aevtSelector & 2) != 0) ? kSelfSendSafe : kDontUseSelfSend;
  1879.         }
  1880.     
  1881.     //
  1882.     // Don't make the self-addressed event unless it is safe to do so
  1883.     //
  1884.     if(gCanUseSelfSend == kSelfSendSafe)
  1885.         {
  1886.         this->MakeAppleEvent(eventClass, eventID, current, returnID, transactionID);
  1887.         }
  1888.     else
  1889.         FailErr(errAEEventNotHandled);
  1890.     } // TAEvent::MakeEventAddressedToSelf 
  1891.  
  1892. //----------------------------------------------------------------------------------------
  1893. // TAEvent::MakeEventAddressedToSystem: 
  1894. //----------------------------------------------------------------------------------------
  1895. void TAEvent::MakeEventAddressedToSystem(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
  1896.     {
  1897.     ProcessSerialNumber systemPSN;        // create psn for the System
  1898.     systemPSN.highLongOfPSN = 0;
  1899.     systemPSN.lowLongOfPSN = kSystemProcess;
  1900.     
  1901.     this->MakeAppleEvent(eventClass, eventID, systemPSN, returnID, transactionID);
  1902.     } // TAEvent::MakeEventAddressedToSystem 
  1903.  
  1904. //----------------------------------------------------------------------------------------
  1905. // TAEvent::Send: 
  1906. //----------------------------------------------------------------------------------------
  1907. void TAEvent::Send( TAEvent* reply,
  1908.                     AESendMode sendMode,
  1909.                     AESendPriority sendPriority,
  1910.                     long timeOutInTicks,
  1911.                     AEIdleUPP idleProc,
  1912.                     AEFilterUPP filterProc)
  1913.     {
  1914.     FailErr(AESend(*this, *reply, sendMode, sendPriority, timeOutInTicks, idleProc, filterProc));
  1915.     } // TAEvent::Send 
  1916.  
  1917. #define kAEDontExecute 0x2000 // for SendMode, when you just want an event recorded, not executed
  1918.  
  1919. //----------------------------------------------------------------------------------------
  1920. // TAEvent::SendNoExecute: 
  1921. //
  1922. // This routine sends the event with the 'kAEDontExecute' bit set, so that the
  1923. // event will be recorded, but the recipient will not execute it.  The event is
  1924. // also sent 'no reply', since it does not make sense to expect a result from
  1925. // a command that is not actually executed.
  1926. //----------------------------------------------------------------------------------------
  1927. void TAEvent::SendNoExecute()
  1928.     {
  1929.     //
  1930.     // The reply isn't actuall filled in due to the kAENoReply flag
  1931.     //
  1932.     TAEvent reply;
  1933.     Send(&reply, kAENoReply+kAEDontExecute);
  1934.     } // TAEvent::SendNoExecute 
  1935.  
  1936.  
  1937. //----------------------------------------------------------------------------------------
  1938. // TAEvent::SuspendTheCurrentEvent: 
  1939. //----------------------------------------------------------------------------------------
  1940. void TAEvent::SuspendTheCurrentEvent()
  1941.     {
  1942.     FailErr(AESuspendTheCurrentEvent(*this));
  1943.     } // TAEvent::SuspendTheCurrentEvent 
  1944.  
  1945. //----------------------------------------------------------------------------------------
  1946. // TAEvent::ResumeTheCurrentEvent: 
  1947. //----------------------------------------------------------------------------------------
  1948. void TAEvent::ResumeTheCurrentEvent(TAEvent* reply, AEEventHandlerUPP dispatcher, long refCon)
  1949.     {
  1950.     FailErr(AEResumeTheCurrentEvent(*this, *reply, dispatcher, refCon));
  1951.     } // TAEvent::ResumeTheCurrentEvent 
  1952.  
  1953. //----------------------------------------------------------------------------------------
  1954. // TAEvent::SetTheCurrentEvent: 
  1955. //----------------------------------------------------------------------------------------
  1956. void TAEvent::SetTheCurrentEvent()
  1957.     {
  1958.     FailErr(AESetTheCurrentEvent(*this));
  1959.     } // TAEvent::SetTheCurrentEvent 
  1960.  
  1961. //----------------------------------------------------------------------------------------
  1962. // TAEvent::ResetTimer: 
  1963. //
  1964. // Note:    requires that this event be a 'reply' event passed to one of our event
  1965. //            handlers by the AppleEvent manager 
  1966. //----------------------------------------------------------------------------------------
  1967. void TAEvent::ResetTimer()
  1968.     {
  1969.     FailErr(AEResetTimer(*this));
  1970.     } // TAEvent::ResetTimer 
  1971.  
  1972. //----------------------------------------------------------------------------------------
  1973. // TAEvent::SpecifyThatParameterIsOptional: 
  1974. //----------------------------------------------------------------------------------------
  1975. void TAEvent::SpecifyThatParameterIsOptional(AEKeyword theOptionalKeyword)
  1976.     {
  1977.     TDescriptor optionalKeywordsList;
  1978.     TDescriptor optionalKeyword;
  1979.     OSErr err = noErr;
  1980.     
  1981.     Try
  1982.         {
  1983.         //
  1984.         // ◊Script:  We need to test to see if keyOptionalKeywordAttr
  1985.         // already exists, and if so, then just add one more element to
  1986.         // the list that is already inside the event.
  1987.         //
  1988.         optionalKeywordsList.MakeList();
  1989.         optionalKeyword.MakeKeyword(theOptionalKeyword);
  1990.         optionalKeywordsList.AddDescriptor(optionalKeyword);
  1991.         optionalKeyword.Dispose();
  1992.         this->PutAttribute(keyOptionalKeywordAttr, optionalKeywordsList);
  1993.         optionalKeywordsList.Dispose();
  1994.         }
  1995.     Catch(err)
  1996.         {
  1997.         optionalKeyword.Dispose();
  1998.         optionalKeywordsList.Dispose();
  1999.         
  2000.         Throw(err);
  2001.         }
  2002.     } // TAEvent::SpecifyThatParameterIsOptional 
  2003.  
  2004. //----------------------------------------------------------------------------------------
  2005. // TAEvent::GetAttribute: 
  2006. //----------------------------------------------------------------------------------------
  2007. TDescriptor TAEvent::GetAttribute(AEKeyword key, DescType desiredType /* = typeWildCard */)
  2008.     {
  2009.     TDescriptor result;
  2010.     
  2011.     FailErr(AEGetAttributeDesc(*this, key, desiredType, result));
  2012.     
  2013.     return result;
  2014.     } // TAEvent::GetAttribute 
  2015.  
  2016. //----------------------------------------------------------------------------------------
  2017. // TAEvent::GetLongAttribute: 
  2018. //----------------------------------------------------------------------------------------
  2019. long TAEvent::GetLongAttribute(AEKeyword key)
  2020.     {
  2021.     DescType typeCode;
  2022.     long actualSize;
  2023.     long result;
  2024.     
  2025.     FailErr(AEGetAttributePtr(*this, key, typeLongInteger, &typeCode, (Ptr)&result, sizeof(long), &actualSize));
  2026.     
  2027.     return result;
  2028.     } // TAEvent::GetLongAttribute 
  2029.  
  2030. //----------------------------------------------------------------------------------------
  2031. // TAEvent::PutAttribute: 
  2032. //----------------------------------------------------------------------------------------
  2033. void TAEvent::PutAttribute(AEKeyword key, TDescriptor attribute)
  2034.     {
  2035.     FailErr(AEPutAttributeDesc(*this, key, attribute));
  2036.     } // TAEvent::PutAttribute 
  2037.  
  2038. //----------------------------------------------------------------------------------------
  2039. // PutOptionalDescriptor: 
  2040. //----------------------------------------------------------------------------------------
  2041. void TAEvent::PutOptionalDescriptor(AEKeyword key, TDescriptor data)
  2042.     {
  2043.     this->PutDescriptor(key, data);
  2044.     this->SpecifyThatParameterIsOptional(key);
  2045.     } // TAEvent::PutOptionalDescriptor 
  2046.  
  2047. //----------------------------------------------------------------------------------------
  2048. // TAEvent::PutLongAttribute: 
  2049. //----------------------------------------------------------------------------------------
  2050. void TAEvent::PutLongAttribute(AEKeyword key, long attributeValue)
  2051.     {
  2052.     FailErr(AEPutAttributePtr(*this, key, typeLongInteger, (Ptr)&attributeValue, sizeof(long)));
  2053.     } // TAEvent::PutLongAttribute 
  2054.     
  2055.  
  2056. //========================================================================================
  2057. // CLASS TTokenDescriptor
  2058. //
  2059. // The class TTokenDescriptor represents descriptors returned by AEResolve
  2060. //========================================================================================
  2061.  
  2062.  
  2063. //----------------------------------------------------------------------------------------
  2064. // TTokenDescriptor::TTokenDescriptor: 
  2065. //----------------------------------------------------------------------------------------
  2066. TTokenDescriptor::TTokenDescriptor()
  2067.     {
  2068.     fDescriptorType = typeNull;
  2069.     fDataHandle = nil;
  2070.     } // TTokenDescriptor::TTokenDescriptor 
  2071.  
  2072. //----------------------------------------------------------------------------------------
  2073. // TTokenDescriptor::TTokenDescriptor: 
  2074. //----------------------------------------------------------------------------------------
  2075. TTokenDescriptor::TTokenDescriptor(TDescriptor desc)
  2076.     {
  2077.     this->fDescriptorType = desc.DescriptorType();
  2078.     this->fDataHandle = desc.DataHandle();
  2079.     } // TTokenDescriptor::TTokenDescriptor 
  2080.     
  2081. //----------------------------------------------------------------------------------------
  2082. // TTokenDescriptor::DisposeToken:
  2083. //
  2084. // It is very important that token descriptors be disposed of by AEDisposeToken,
  2085. // _not_ AEDisposeDesc.
  2086. //----------------------------------------------------------------------------------------
  2087. void TTokenDescriptor::DisposeToken()
  2088.     {
  2089.     AEDisposeToken(*this);  // Should fail on error?  Probably not.
  2090.  
  2091.     // FailErr(AEDisposeDesc(*this));
  2092.     } // TTokenDescriptor::DisposeToken 
  2093.  
  2094.  
  2095. //----------------------------------------------------------------------------------------
  2096. // TTokenDescriptor::TokenHandle:
  2097. //
  2098. // Return the TTokenObject stored inside the token descriptor
  2099. //----------------------------------------------------------------------------------------
  2100. TAbstractScriptableObject* TTokenDescriptor::TokenHandle()
  2101.     {
  2102.     Handle tokenHandle = this->DataHandle();
  2103.     TAbstractScriptableObject* tokenObject = nil;
  2104.     
  2105.     if((this->DescriptorType() != typeTokenObject) || (tokenHandle == nil))
  2106.         {
  2107.         //
  2108.         // ••• What error code should we fail with here?
  2109.         //
  2110.         FailErr(errAENoSuchObject);
  2111.         }
  2112.     
  2113.     //
  2114.     // tokenHandle is a handle that contains a TTokenObject*,
  2115.     // so it is a pointer to a pointer to a TTokenObject* (wow)
  2116.     //
  2117.     tokenObject = ** ((TAbstractScriptableObject***) tokenHandle);
  2118.     return tokenObject;
  2119.     } // TTokenDescriptor::TokenHandle 
  2120.  
  2121.  
  2122. //----------------------------------------------------------------------------------------
  2123. // TTokenDescriptor::AdoptToken:
  2124. //
  2125. // IMPORTANT: ADOPTS THE TOKEN PASSED TO IT
  2126. //----------------------------------------------------------------------------------------
  2127. void TTokenDescriptor::AdoptToken(TTokenDescriptor& tokenDescriptor)
  2128.     {
  2129.     //
  2130.     // Don't adopt the new token if it is empty
  2131.     //
  2132.     if(tokenDescriptor.IsNullDescriptor() == false)
  2133.         {
  2134.         //
  2135.         // If this descriptor is empty, it is easy to adopt the new token
  2136.         //
  2137.         if( this->IsNullDescriptor() )
  2138.             {
  2139.             TDescriptor::AdoptHandle(tokenDescriptor.DescriptorType(), tokenDescriptor.DataHandle() );
  2140.             tokenDescriptor.MakeNull();
  2141.             }
  2142.         else
  2143.             {
  2144.             TAbstractScriptableObject* tokenObject = tokenDescriptor.TokenHandle();
  2145.             this->AdoptToken(tokenObject);
  2146.             
  2147.             //
  2148.             // n.b.    'Dispose', not 'DisposeToken'.  The token that
  2149.             // was formerly contained in tokenDescriptor is now referenced
  2150.             // in 'this' token descriptor, so it would be a bad idea to
  2151.             // delete it.
  2152.             //
  2153.             tokenDescriptor.Dispose();
  2154.             }
  2155.         }
  2156.     } // TTokenDescriptor::AdoptToken 
  2157.  
  2158. //----------------------------------------------------------------------------------------
  2159. // TTokenDescriptor::AdoptToken: 
  2160. //----------------------------------------------------------------------------------------
  2161. void TTokenDescriptor::AdoptToken(TAbstractScriptableObject* tokenObject)
  2162.     {
  2163.     //
  2164.     // Don't adopt the new token if it is not a valid object
  2165.     //
  2166.     if(tokenObject != nil)
  2167.         {
  2168.         //
  2169.         // If this descriptor is empty, then create a new
  2170.         // token descriptor to hold a pointer to the tokenObject.
  2171.         //
  2172.         if(this->IsNullDescriptor() )
  2173.             {
  2174.             Handle newHandle = NewHandle( sizeof(Ptr) );
  2175.             ** ((TAbstractScriptableObject***)newHandle) = tokenObject;
  2176.             
  2177.             TDescriptor::AdoptHandle(typeTokenObject, newHandle);
  2178.             }
  2179.         //
  2180.         // If there is already something here, then we need
  2181.         // to somehow merge the two tokens together.  In the
  2182.         // Scriptable Finder, we want to create a mark token
  2183.         // to do the merge.  However, MoreAEM does not depend
  2184.         // on files such as MarkToken.h which are outside of
  2185.         // the Blue folder.  Therefore, we call a callback proc
  2186.         // to fill in the mark token.  The callback proc is
  2187.         // installed in InitializeScriptability.
  2188.         //
  2189.         else
  2190.             {
  2191.             if(gMergeTokensProc == nil)
  2192.                 FailErr(errAEEventNotHandled);
  2193.                 
  2194.             //
  2195.             // The MergeTokensProc takes two TAbstractScriptableObject*'s
  2196.             // and merges them into another TAbstractScriptableObject*
  2197.             // (which adopts the two original tokens).
  2198.             //
  2199.             TAbstractScriptableObject* mergedTokens = (*gMergeTokensProc)(this->TokenHandle(), tokenObject);
  2200.  
  2201.             Handle tokenHandle = this->DataHandle();
  2202.             ** ((TAbstractScriptableObject***) tokenHandle) = mergedTokens;
  2203.             }
  2204.         }
  2205.     } // TTokenDescriptor::AdoptToken 
  2206.  
  2207.  
  2208. #pragma segment CFrontCruft
  2209.